package flib;

import java.io.File;
import java.util.Vector;

import javax.swing.JFileChooser;

import blobDetector.Blob;
import blobDetector.BlobDetector;

import analyses.DepthAnalyser2D;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PImage;
import simpleGeom.Polygon2D;

public class PixelFloorApplet extends PApplet {
	PImage imgFloorplan;
	float[][] gridBrightness;
	Object[][] areas;
	float treshhold = 100;
	float[][] gridAnalyse;
	int nX;
	int nY;
	final static int BLACK = 0;
	final static int WHITE = 255;
	final static int BORDER = 255;
	Pixel[][] grid;
	Vector<Pixel> outside;
	Vector<Blob> blobs;
	Vector<Blob> roomBlobs;
	PGraphics roomblobsGraphics;
	float[][] border;
	String pathImage = "/Users/administrator/projekte/Doktor/work/Floorplans/b1p031i77f0n210.jpg";

	public void setup() {
		size(1200, 800, P2D);

		imgFloorplan = this.loadImage(pathImage);
		setupPlan();

	}

	float[][] rooms;
	float[][] invert;

	public float[][] shrinkBlackDist(float[][] input, float dist) {

		float[][] blackDist = DepthAnalyser2D.getDepth(input);
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				float d = blackDist[x][y];
				if (blackDist[x][y] > dist) {
					blackDist[x][y] = 0;
				} else {
					blackDist[x][y] = 255;
				}
			}
		}
		return blackDist;
	}

	public void collectBorders() {
		border = new float[nX][nY];
		Vector<Pixel> candidates = new Vector<Pixel>();
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y += nY - 1) {
				Pixel p = grid[x][y];

				candidates.add(p);

			}
		}
		for (int y = 0; y < nY; y++) {
			for (int x = 0; x < nX; x += nX - 1) {
				Pixel p = grid[x][y];

				candidates.add(p);

			}
		}
		outside = reach(candidates, 100);
		for (int i = 0; i < outside.size(); i++) {
			Pixel p = outside.get(i);
			border[p.x][p.y] = BORDER;
		}
	}

	// depth shrink.
	// depth grow.
	public Vector<Pixel> reach(Vector<Pixel> candidates, float iso) {
		Vector<Pixel> reached = new Vector<Pixel>();
		for (int i = 0; i < candidates.size(); i++) {
			Pixel pixel = candidates.get(i);
			pixel.checked = true;
			reached.add(pixel);
		}

		while (candidates.size() > 0) {
			Vector<Pixel> nextCandidates = new Vector<Pixel>();
			for (int i = 0; i < candidates.size(); i++) {
				Pixel pixel = candidates.get(i);
				int x = pixel.x;
				int y = pixel.y;
				int x1 = max(x - 1, 0);
				int y1 = max(y - 1, 0);
				int x2 = min(nX, x + 2);
				int y2 = min(nY, y + 2);
				for (int cX = x1; cX < x2; cX++) {
					for (int cY = y1; cY < y2; cY++) {
						Pixel nb = grid[cX][cY];
						if (!nb.checked && nb.brightness > iso) {
							nb.checked = true;
							nextCandidates.add(nb);
							reached.add(nb);
						}
					}
				}

			}
			candidates = nextCandidates;
		}
		return reached;
	}

	public void setupPlan() {

		nX = imgFloorplan.width;
		nY = imgFloorplan.height;
		roomblobsGraphics = createGraphics(nX, nY, P2D);
		gridBrightness = new float[nX][nY];
		grid = new Pixel[nX][nY];
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				if (x == 0 || x == nX - 1 || y == 0 || y == nY - 1) {
					imgFloorplan.set(x, y, color(255));
				}
			}
		}

		// imgFloorplan.updatePixels();
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				int col = imgFloorplan.get(x, y);
				float br = brightness(col);
				Pixel pixel = new Pixel(x, y);
				pixel.brightness = br;
				grid[x][y] = pixel;
				gridBrightness[x][y] = br;
			}
		}
		collectBorders();
		float[][] black = new float[nX][nY];
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				int col = imgFloorplan.get(x, y);
				float br = brightness(col);
				if (br > 100)
					black[x][y] = 0;
				else {
					black[x][y] = 1000;
				}
			}
		}
		gridAnalyse = shrinkBlackDist(black, 3);
		invert = new float[nX][nY];
		for (int x = 0; x < gridAnalyse.length; x++) {
			for (int y = 0; y < gridAnalyse[0].length; y++) {
				if (gridAnalyse[x][y] == 0) {
					invert[x][y] = 0;
				} else {
					invert[x][y] = 1000;
				}
			}
		}
		invert = shrinkBlackDist(invert, 3);

		BlobDetector bD = new BlobDetector(nX, nY);
		bD.setValues(invert);
		bD.calculateBlobs(100);
		blobs = bD.getBlobs();

		println("blobs" + blobs.size());
		for (int i = 0; i < blobs.size(); i++) {
			Blob blob = blobs.get(i);
			if (abs(Polygon2D.getArea(blob.getBorders())) < 200) {
				fill(0, 0, 255);
				for (int x = blob.getMinX(); x < blob.getMaxX(); x++) {
					for (int y = blob.getMinY(); y < blob.getMaxY(); y++) {
						if (Polygon2D.contains(x, y, blob.getBorders())) {
							invert[x][y] = 0;
						}
					}
				}
			}
		}

		rooms = new float[nX][nY];
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				if (invert[x][y] == 0) {
					rooms[x][y] = 1000;
				} else {
					rooms[x][y] = 0;
				}
			}
		}
		rooms = shrinkBlackDist(rooms, 60);
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				if (rooms[x][y] == 0) {
					rooms[x][y] = 0;
				} else {
					rooms[x][y] = 1000;
				}
			}
		}
		rooms = shrinkBlackDist(rooms, 50);
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				if (rooms[x][y] == 0) {
					rooms[x][y] = 1000;
				} else {
					rooms[x][y] = 0;
				}
				if (invert[x][y] == 255) {
					rooms[x][y] = 0;
				}

			}
		}
		bD.setValues(rooms);
		bD.calculateBlobs(1);
		roomBlobs = bD.getBlobs();
		println("i: " + roomBlobs.size());
		areas = new Area[nX][nY];

		roomblobsGraphics.beginDraw();
		roomblobsGraphics.noStroke();
		Vector<Area> areaList = new Vector<Area>();
		for (int i = 0; i < roomBlobs.size(); i++) {
			roomblobsGraphics.fill(i + 1);
			Area area = new Area();
			area.color = color(random(255), random(255), random(255));
			areaList.add(area);
			Blob blob = roomBlobs.get(i);
			Polygon2D.display(roomblobsGraphics, blob.getBorders());
		}
		/*
		 * Area outsideArea=new Area(); areaList.add(outsideArea); for (int
		 * x=0;x<nX;x++){ for (int y=0;y<nY;y++){ int
		 * col=roomblobsGraphics.get(x, y); int b=(int)brightness(col); if
		 * (b>0){ Area area=areaList.get(b-1); areas[x][y]=area; } if
		 * (border[x][y]>0){ areas[x][y]=outsideArea; } } }
		 */

		DepthAnalyser2D dA = new DepthAnalyser2D();
		dA.calculateObjectDepth(areas);
		areas = dA.getDistribution();
	}

	public void draw() {

		float scaleW = width * 0.25f * 1f / nX;
		float scaleH = height * 1f / nY;
		float scaleMin = min(scaleW, scaleH);
		scale(scaleMin, scaleMin);
		image(imgFloorplan, 0, 0);
		noStroke();
		translate(width * 0.25f / scaleMin, 0);
		fill(255, 0, 0);
		for (int x = 0; x < gridAnalyse.length; x++) {
			for (int y = 0; y < gridAnalyse[x].length; y++) {
				float b = gridAnalyse[x][y];
				if (gridAnalyse[x][y] < 255) {
					fill(255, 0, 0);
					rect(x, y, 1, 1);
				}
				if (invert[x][y] == 255) {
					fill(0);
					rect(x, y, 1, 1);
				}
			}
		}
		for (int i = 0; i < outside.size(); i++) {
			Pixel cell = outside.get(i);
			fill(0, 255, 255);
			rect(cell.x, cell.y, 1, 1);
		}
		noFill();
		stroke(255, 0, 255);
		for (int i = 0; i < blobs.size(); i++) {
			Blob blob = blobs.get(i);
			// Area area=areas.get(i);
			if (abs(Polygon2D.getArea(blob.getBorders())) < 200) {
				// fill(0,0,255);
			} else {
				noFill();
			}

			Polygon2D.display(g, blob.getBorders());
		}
		translate(width * 0.25f / scaleMin, 0);
		/*
		 * for (int x=0;x<nX;x++){ for (int y=0;y<nY;y++){ float b=rooms[x][y];
		 * if (b==0){ fill(255,0,255); rect(x,y,1,1); } } }
		 */

		noStroke();
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				Area area = (Area) areas[x][y];

				// fill(area.color);
				rect(x, y, 1, 1);
			}
		}
		noFill();

		stroke(0, 255, 0);

		for (int i = 0; i < roomBlobs.size(); i++) {
			Blob blob = roomBlobs.get(i);
			fill(i * 255f / roomBlobs.size(), 200, 200);
			// Polygon.display(g, blob.getBorders());
		}

	}

	public class Pixel {
		public Pixel(int x, int y) {
			this.x = x;
			this.y = y;
		}

		float brightness;
		int x;
		int y;
		boolean checked;
	}

	public class Area {
		int color;
	}

}